package com.phoenix.shuaidatabase.single;

import java.lang.reflect.Method;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Function;

public class ShuaiCommand {

    public static final ConcurrentHashMap<String,ShuaiCommand> commands = new ConcurrentHashMap<String,ShuaiCommand>(){{
        try {
            commands.put("GET",new ShuaiCommand("GET", null, ShuaiObject.class.getMethod("get", ShuaiInput.class),2,false,false,null));
            commands.put("SET",new ShuaiCommand("SET", ShuaiString::set, ShuaiString.class.getMethod("set", ShuaiInput.class),3,true,true,ShuaiObjectType.SHUAI_STRING));
            commands.put("GETRANGE", new ShuaiCommand("GETRANGE", null, ShuaiString.class.getMethod("getRange", ShuaiInput.class), 4, false,false,ShuaiObjectType.SHUAI_STRING));
            commands.put("SETRANGE", new ShuaiCommand("SETRANGE", ShuaiString::setRange, ShuaiString.class.getMethod("setRange", ShuaiInput.class), 4, true,true,ShuaiObjectType.SHUAI_STRING));
            commands.put("STRLEN", new ShuaiCommand("STRLEN", null, ShuaiString.class.getMethod("strLen", ShuaiInput.class), 2, false,false,ShuaiObjectType.SHUAI_STRING));
            commands.put("INCRBY", new ShuaiCommand("INCRBY", null, ShuaiString.class.getMethod("incrBy", ShuaiInput.class), 3, false,true,ShuaiObjectType.SHUAI_STRING));
            commands.put("INCRBYFLOAT", new ShuaiCommand("INCRBYFLOAT", null, ShuaiString.class.getMethod("incrByFloat", ShuaiInput.class), 3, false,true,ShuaiObjectType.SHUAI_STRING));
            commands.put("DECRBY", new ShuaiCommand("DECRBY", null, ShuaiString.class.getMethod("decrBy", ShuaiInput.class), 3, false,true,ShuaiObjectType.SHUAI_STRING));
            commands.put("DECRBYFLOAT", new ShuaiCommand("DECRBYFLOAT", null, ShuaiString.class.getMethod("decrByFloat", ShuaiInput.class), 3, false,true,ShuaiObjectType.SHUAI_STRING));
            commands.put("LPUSH", new ShuaiCommand("LPUSH", ShuaiList::lPush, ShuaiList.class.getMethod("lPush", ShuaiInput.class), 3, true,true,ShuaiObjectType.SHUAI_LIST));
            commands.put("RPUSH", new ShuaiCommand("RPUSH", ShuaiList::rPush, ShuaiList.class.getMethod("rPush", ShuaiInput.class), 3, true,true,ShuaiObjectType.SHUAI_LIST));
            commands.put("LRANGE", new ShuaiCommand("LRANGE", null, ShuaiList.class.getMethod("lRange", ShuaiInput.class), 4, false, false,ShuaiObjectType.SHUAI_LIST));
            commands.put("LPOP", new ShuaiCommand("LPOP", null, ShuaiList.class.getMethod("lPop", ShuaiInput.class), 2, false, true,ShuaiObjectType.SHUAI_LIST));
            commands.put("RPOP", new ShuaiCommand("RPOP", null, ShuaiList.class.getMethod("rPop", ShuaiInput.class), 2,  false, true,ShuaiObjectType.SHUAI_LIST));
            commands.put("LLEN", new ShuaiCommand("LLEN", null, ShuaiList.class.getMethod("lLen", ShuaiInput.class), 2,  false, false,ShuaiObjectType.SHUAI_LIST));
            commands.put("LINDEX", new ShuaiCommand("LINDEX", null, ShuaiList.class.getMethod("lIndex", ShuaiInput.class), 3,  false, false, ShuaiObjectType.SHUAI_LIST));
            commands.put("LINSERT", new ShuaiCommand("LINSERT", null, ShuaiList.class.getMethod("lInsert", ShuaiInput.class), 5,  false, true, ShuaiObjectType.SHUAI_LIST));
            commands.put("LREM", new ShuaiCommand("LREM", null, ShuaiList.class.getMethod("lRem", ShuaiInput.class), 4,  false, true, ShuaiObjectType.SHUAI_LIST));
            commands.put("LTRIM", new ShuaiCommand("LTRIM", null, ShuaiList.class.getMethod("lTrim", ShuaiInput.class), 4,  false, true, ShuaiObjectType.SHUAI_LIST));
            commands.put("LSET", new ShuaiCommand("LSET", null, ShuaiList.class.getMethod("lSet", ShuaiInput.class), 4,  false, true, ShuaiObjectType.SHUAI_LIST));
            commands.put("HGET", new ShuaiCommand("HGET", null, ShuaiHash.class.getMethod("hGet", ShuaiInput.class), 3,  false, false, ShuaiObjectType.SHUAI_HASH));
            commands.put("HSET", new ShuaiCommand("HSET", ShuaiHash::hSet, ShuaiHash.class.getMethod("hSet", ShuaiInput.class), 4,  true, true, ShuaiObjectType.SHUAI_HASH));
            commands.put("HEXIST", new ShuaiCommand("HEXIST", null, ShuaiHash.class.getMethod("hExist", ShuaiInput.class), 3,  false, false, ShuaiObjectType.SHUAI_HASH));
            commands.put("HLEN", new ShuaiCommand("HLEN", null, ShuaiHash.class.getMethod("hLen", ShuaiInput.class), 2,  false, false, ShuaiObjectType.SHUAI_HASH));
            commands.put("HGETALL", new ShuaiCommand("HGETALL", null, ShuaiHash.class.getMethod("hGetAll", ShuaiInput.class), 2,  false, false, ShuaiObjectType.SHUAI_HASH));
            commands.put("HDEL", new ShuaiCommand("HDEL", null, ShuaiHash.class.getMethod("hDel", ShuaiInput.class), 3,  false, true, ShuaiObjectType.SHUAI_HASH));
            commands.put("HMSET", new ShuaiCommand("HMSET", ShuaiHash::hMSet, ShuaiHash.class.getMethod("hMSet", ShuaiInput.class), 4,  true, true, ShuaiObjectType.SHUAI_HASH));
            commands.put("EXPIRE", new ShuaiCommand("EXPIRE", null, ShuaiObject.class.getMethod("expire", ShuaiInput.class), 3,  false, true, null));
            commands.put("PEXPIRE", new ShuaiCommand("PEXPIRE", null, ShuaiObject.class.getMethod("pExpire", ShuaiInput.class), 3,  false, true, null));
            commands.put("DEL",new ShuaiCommand("DEL", ShuaiObject::delete ,ShuaiObject.class.getMethod("delete", ShuaiInput.class),2,true,true,null));
            commands.put("SADD",new ShuaiCommand("SADD", ShuaiSet::sadd ,ShuaiSet.class.getMethod("sadd", ShuaiInput.class),3,true,true,ShuaiObjectType.SHUAI_SET));
            commands.put("SCARD",new ShuaiCommand("SCARD", null,ShuaiSet.class.getMethod("scard", ShuaiInput.class),2,false,false,ShuaiObjectType.SHUAI_SET));
            commands.put("SDIFF",new ShuaiCommand("SDIFF", null,ShuaiSet.class.getMethod("sdiff", ShuaiInput.class),3,false,false,ShuaiObjectType.SHUAI_SET));
            commands.put("SDIFFSTORE",new ShuaiCommand("SDIFFSTORE", null,ShuaiSet.class.getMethod("sdiffstore", ShuaiInput.class),4,false,true,ShuaiObjectType.SHUAI_SET));
            commands.put("SUNION",new ShuaiCommand("SUNION", null,ShuaiSet.class.getMethod("sunion", ShuaiInput.class),3,false,false,ShuaiObjectType.SHUAI_SET));
            commands.put("SUNIONSTORE",new ShuaiCommand("SUNIONSTORE", null,ShuaiSet.class.getMethod("sunionstore", ShuaiInput.class),4,false,true,ShuaiObjectType.SHUAI_SET));
            commands.put("SINTER",new ShuaiCommand("SINTER", null,ShuaiSet.class.getMethod("sinter", ShuaiInput.class),3,false,false,ShuaiObjectType.SHUAI_SET));
            commands.put("SINTERSTORE",new ShuaiCommand("SINTERSTORE", null,ShuaiSet.class.getMethod("sinterstore", ShuaiInput.class),4,false,false,ShuaiObjectType.SHUAI_SET));
            commands.put("SMEMBERS",new ShuaiCommand("SMEMBERS", null,ShuaiSet.class.getMethod("smembers", ShuaiInput.class),2,false,false,ShuaiObjectType.SHUAI_SET));
            commands.put("SMOVE",new ShuaiCommand("SMOVE", null,ShuaiSet.class.getMethod("smove", ShuaiInput.class),4,false,true,ShuaiObjectType.SHUAI_SET));
            commands.put("SISMEMBER",new ShuaiCommand("SISMEMBER", null,ShuaiSet.class.getMethod("sismember", ShuaiInput.class),3,false,false,ShuaiObjectType.SHUAI_SET));
            commands.put("SREM",new ShuaiCommand("SREM", null,ShuaiSet.class.getMethod("srem", ShuaiInput.class),3,false,true,ShuaiObjectType.SHUAI_SET));
            commands.put("SPOP",new ShuaiCommand("SPOP", null,ShuaiSet.class.getMethod("spop", ShuaiInput.class),3,false,true,ShuaiObjectType.SHUAI_SET));
            commands.put("SRANDMEMBER",new ShuaiCommand("SRANDMEMBER", null,ShuaiSet.class.getMethod("srandmember", ShuaiInput.class),3,false,false,ShuaiObjectType.SHUAI_SET));
            commands.put("ZADD",new ShuaiCommand("ZADD", ShuaiZset::zadd ,ShuaiZset.class.getMethod("zadd", ShuaiInput.class),3,true,true,ShuaiObjectType.SHUAI_ZSET));
            commands.put("ZCARD",new ShuaiCommand("ZCARD", null,ShuaiZset.class.getMethod("zsetLength",ShuaiInput.class),2,false,false,ShuaiObjectType.SHUAI_ZSET));
            commands.put("ZCOUNT",new ShuaiCommand("ZCOUNT", null,ShuaiZset.class.getMethod("zcount", ShuaiInput.class),4,false,false,ShuaiObjectType.SHUAI_ZSET));
            commands.put("ZINCRBY",new ShuaiCommand("ZINCRBY", null,ShuaiZset.class.getMethod("zincrby", ShuaiInput.class),3,false,true,ShuaiObjectType.SHUAI_ZSET));
            commands.put("ZINTERSTORE",new ShuaiCommand("ZINTERSTORE", null,ShuaiZset.class.getMethod("zinterstore", ShuaiInput.class),4,false,true,ShuaiObjectType.SHUAI_ZSET));
            commands.put("ZRANGEBYSCORE",new ShuaiCommand("ZRANGEBYSCORE", null,ShuaiZset.class.getMethod("zrangeByScore", ShuaiInput.class),4,false,false,ShuaiObjectType.SHUAI_ZSET));
            commands.put("ZRANGE",new ShuaiCommand("ZRANGE", null,ShuaiZset.class.getMethod("zrange", ShuaiInput.class),4,false,false,ShuaiObjectType.SHUAI_ZSET));
            commands.put("ZRANK",new ShuaiCommand("ZRANK", null,ShuaiZset.class.getMethod("zrank", ShuaiInput.class),3,false,false,ShuaiObjectType.SHUAI_ZSET));
            commands.put("ZREM",new ShuaiCommand("ZREM", null,ShuaiZset.class.getMethod("zrem", ShuaiInput.class),3,false,true,ShuaiObjectType.SHUAI_ZSET));
            commands.put("ZREMRANGEBYRANK",new ShuaiCommand("ZREMRANGEBYRANK", null,ShuaiZset.class.getMethod("zremRangeByRank", ShuaiInput.class),4,false,true,ShuaiObjectType.SHUAI_ZSET));
            commands.put("ZREMRANGEBYSCORE",new ShuaiCommand("ZREMRANGEBYSCORE", null,ShuaiZset.class.getMethod("zremRangeByScore", ShuaiInput.class),4,false,true,ShuaiObjectType.SHUAI_ZSET));
            commands.put("ZREVRANGE",new ShuaiCommand("ZREVRANGE", null,ShuaiZset.class.getMethod("zrevRange", ShuaiInput.class),4,false,false,ShuaiObjectType.SHUAI_ZSET));
            commands.put("ZREVRANGEBYSCORE",new ShuaiCommand("ZREVRANGEBYSCORE", null,ShuaiZset.class.getMethod("zrevRangeByScore", ShuaiInput.class),4,false,false,ShuaiObjectType.SHUAI_ZSET));
            commands.put("ZREVRANK",new ShuaiCommand("ZREVRANK", null,ShuaiZset.class.getMethod("zrevRank", ShuaiInput.class),3,false,false,ShuaiObjectType.SHUAI_ZSET));
            commands.put("ZSCORE",new ShuaiCommand("ZSCORE", null,ShuaiZset.class.getMethod("zscore", ShuaiInput.class),3,false,false,ShuaiObjectType.SHUAI_ZSET));
            commands.put("SELECT",new ShuaiCommand("SELECT", ShuaiObject::select ,ShuaiObject.class.getMethod("select", ShuaiInput.class),2,true,true,null));
            commands.put("TTL",new ShuaiCommand("TTL", null,ShuaiObject.class.getMethod("ttl", ShuaiInput.class),2,false,false,null));
            commands.put("PTTL",new ShuaiCommand("PTTL", null,ShuaiObject.class.getMethod("pttl", ShuaiInput.class),2,false,false,null));
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
    }};

    private final String name;

    private final Method proc;

    private Function<ShuaiInput, ShuaiReply> func;

    private final int arity;

    private final AtomicInteger calls;

    private Long milliseconds;

    private final boolean staticOrNot;

    private final boolean willModify;

    private final ShuaiObjectType type;

    public ShuaiCommand(String name, Function<ShuaiInput, ShuaiReply> func, Method proc, int arity, boolean staticOrNot,boolean willModify,ShuaiObjectType type) {
        this.name = name;
        this.func = func;
        this.proc = proc;
        this.arity = arity;
        this.calls = new AtomicInteger(0);
        this.staticOrNot = staticOrNot;
        this.willModify = willModify;
        this.type = type;
    }

    public String getName() {
        return name;
    }

    public Function<ShuaiInput, ShuaiReply> getFunc() {
        return func;
    }
    
    public Method getProc() {
        return proc;
    }

    public int getArity() {
        return arity;
    }

    public boolean isStaticOrNot() {
        return staticOrNot;
    }

    public int getCalls() {
        return calls.get();
    }

    public long getMilliseconds() {
        return milliseconds;
    }

    public void setMilliseconds(Long milliseconds) {
        this.milliseconds = milliseconds;
    }

    public int increaseCalls() {
        return this.calls.incrementAndGet();
    }

    public boolean isWillModify() {
        return willModify;
    }

    public ShuaiObjectType getType() {
        return type;
    }
}
